
/*
  TimeKeeper

  Description:
  
    concept TimeKeeper:
	    void   start();
		void   stop();
		Time   getTime();
        Scalar [get|set]DesiredTickRate();
		Time   [get|set]MeasureTime();
		Scalar getMomentRate();
		Scalar getTickRate();
		
    TimeKeeper is a statically-interfaced class that
	maintains time and passes time-based events to a
    statically-interfaced Handler concept defined as:
    
	concept Handler:
        onMoment(TimeKeeper* caller);
		onTick(TimeKeeper* caller);
		
    Two units of time are defined:
      Moments occur as fast as possible
	  Ticks occur at a specified rate
*/

#ifndef _TIMEKEEPER_HPP
#define _TIMEKEEPER_HPP

#include "IClock.hpp"
#include "Maths.hpp"

template<class Handler>
class TimeKeeper
{
	Handler* m_handler;
	
	IClock* m_clock;
	Scalar  m_desired_tick_rate;
	Scalar  m_tick_rate;
	Scalar  m_moment_rate;
	Time    m_measure_time; // Measurements avgd over this
	/*
	Scalar  m_tick_duration;
	size_t  m_tick_count;
	size_t  m_moment_count;
	Time    m_last_tick_time;
	Time    m_last_measure_time;
	*/
	bool    m_running;
	
public:
	TimeKeeper(Handler* handler, IClock* clock,
			   Scalar desired_tick_rate=30.0,
			   Time measure_time=1000)
		: m_handler(handler), m_clock(clock),
		  m_desired_tick_rate(desired_tick_rate),
		  m_measure_time(measure_time)
	{
		
	}
	~TimeKeeper() {}
	
	void start();
	void stop()   { m_running = false; }
	
	const Time& getTime() const { return m_clock->getTicks(); }
	
	const Scalar& getDesiredTickRate() const
	{ return m_desired_tick_rate; }
	Scalar&       getDesiredTickRate()             
	{ return m_desired_tick_rate; }
	void          setDesiredTickRate(const Scalar& desired_tick_rate)
	{ m_desired_tick_rate = desired_tick_rate; }
	
	const Time& getMeasureTime() const
	{ return m_measure_time; }
	Time&       getMeasureTime()
	{ return m_measure_time; }
	void          setMeasureTime(const Time& measure_time)
	{ m_measure_time = measure_time; }
	
	const Scalar& getTickRate() const  { return m_tick_rate; }
	const Scalar& getMomentRate() const { return m_moment_rate; }
};

template<class Handler>
void TimeKeeper<Handler>::start()
{
	// Initialise timing variables
	Scalar tick_duration = 1000.0 / (Scalar)m_desired_tick_rate;
	size_t tick_count = 0;
	size_t moment_count = 0;
	Time   last_tick_time = m_clock->getTicks();
	Time   last_measure_time = m_clock->getTicks();
	
	m_running = true;
	while( m_running ) {
		// Perform timekeeping
		// Note: This line enables time acceleration
		//tick_duration = 1.0 / (Scalar)tick_rate * (1.0-time_accel)
		while( last_tick_time + tick_duration <= m_clock->getTicks() ) {
			m_handler->onTick(this);
			++tick_count;
			last_tick_time += (Time)tick_duration;
		}
		m_handler->onMoment(this);
		++moment_count;
		
		// Measure actual tick and frame rates
		Time dt = m_clock->getTicks() - last_measure_time;
		if( dt > m_measure_time ) {
			m_tick_rate = 1000*(Scalar)tick_count / dt;
			m_moment_rate = 1000*(Scalar)moment_count / dt;
			tick_count = 0;
			moment_count = 0;
			last_measure_time = m_clock->getTicks();
		}
	}
}

#endif //_TIMEKEEPER_HPP
